Avec DocuGenerate, vous pouvez créer des documents PDF et Word directement depuis votre application Go. Ce guide montre comment appeler chaque méthode de l’API depuis Go 1.18 ou une version ultérieure. Pour la liste complète des paramètres et des réponses, consultez la référence de l’API.
1. Authentification
2. Créer un modèle
3. Lister les modèles
4. Récupérer un modèle
5. Mettre à jour un modèle
6. Supprimer un modèle
7. Générer un document
8. Lister les documents
9. Récupérer un document
10. Mettre à jour un document
11. Supprimer un document
Chaque requête est authentifiée en envoyant votre clé API dans l’en-tête Authorization. Stockez la clé dans une variable d’environnement plutôt que de l’écrire en dur dans votre code source :
export DOCUGENERATE_API_KEY="YOUR-API-KEY"
Les exemples utilisent les packages net/http, mime/multipart et encoding/json de la bibliothèque standard de Go, il n’y a donc rien à installer. Chaque exemple est écrit comme le corps de la fonction main d’un programme avec ces imports et déclarations. Supprimez les imports qu’un exemple n’utilise pas, car Go ne compile pas les imports inutilisés. Comme net/http ne renvoie pas d’erreur sur les statuts d’erreur HTTP, chaque exemple vérifie le code de statut avant de lire la réponse :
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
const apiURL = "https://api.docugenerate.com/v1"
var apiKey = os.Getenv("DOCUGENERATE_API_KEY")
func main() {
// Add the example code here
}
Si votre compte stocke ses données dans une autre région, remplacez l’URL de base par l’endpoint régional correspondant, par exemple https://api.eu.docugenerate.com/v1.
Pour créer un modèle, envoyez le fichier du modèle avec une requête POST /template. Cet endpoint exige le type de contenu multipart/form-data, construit ici avec un multipart.Writer :
file, err := os.Open("Business Letter.docx")
if err != nil {
panic(err)
}
defer file.Close()
var form bytes.Buffer
writer := multipart.NewWriter(&form)
part, err := writer.CreateFormFile("file", "Business Letter.docx")
if err != nil {
panic(err)
}
if _, err := io.Copy(part, file); err != nil {
panic(err)
}
writer.WriteField("name", "Business Letter")
writer.Close()
request, err := http.NewRequest("POST", apiURL+"/template", &form)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
request.Header.Set("Content-Type", writer.FormDataContentType())
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
var template map[string]any
if err := json.Unmarshal(body, &template); err != nil {
panic(err)
}
fmt.Println(template["id"])
Définissez toujours l’en-tête Content-Type avec writer.FormDataContentType(), qui inclut le séparateur multipart. Sans le séparateur, la requête échoue. La réponse contient le nouveau modèle, y compris les tags détectés automatiquement dans le fichier :
{
"enhanced_syntax": false,
"versioning_enabled": false,
"folder": [],
"tags": {
"valid": [
"Date",
"Name",
"Job Title",
"Company Name",
"Street Address",
"City",
"State",
"Zip Code",
"Email",
"Phone"
],
"invalid": []
},
"created": 1791055374301,
"updated": 1791055374301,
"name": "Business Letter",
"delimiters": {
"left": "[",
"right": "]"
},
"filename": "Business Letter.docx",
"format": ".docx",
"region": "eu",
"page_count": 1,
"image_uri": "https://firebasestorage.googleapis.com/v0/b/storage.eu.docugenerate.com/o/templates%2FuVE30i1427KQsYcED0bl%2FBusiness%20Letter.png?alt=media&token=0ce64a4b-495a-426b-8783-42b479f7ae38",
"preview_uri": "https://firebasestorage.googleapis.com/v0/b/storage.eu.docugenerate.com/o/templates%2FuVE30i1427KQsYcED0bl%2FBusiness%20Letter.pdf?alt=media&token=0b3939c7-824e-4979-9aca-ca4a87175cbf",
"template_uri": "https://firebasestorage.googleapis.com/v0/b/storage.eu.docugenerate.com/o/templates%2FuVE30i1427KQsYcED0bl%2FBusiness%20Letter.docx?alt=media&token=d37a4458-3620-48db-94b8-6ac46f0442ab",
"id": "uVE30i1427KQsYcED0bl"
}
Conservez l’id du modèle, car vous en aurez besoin pour générer des documents. Les paramètres facultatifs suivants peuvent aussi être écrits dans le formulaire :
delimiters : Les délimiteurs utilisés pour détecter les balises, envoyés sous forme de chaîne JSON, par exemple {"left": "[", "right": "]"}. Par défaut, ils sont déterminés automatiquement.region : Où sont stockés le modèle et ses documents générés, soit us, eu, uk ou au. Si aucune région n’est indiquée, celle du compte est utilisée.enhanced_syntax : Définissez sur "true" pour utiliser des propriétés imbriquées et des opérateurs logiques ou mathématiques dans les balises.versioning_enabled : Définissez sur "true" pour conserver les versions précédentes du fichier lors de l’envoi d’un nouveau, si votre forfait le permet.folder : Le dossier du modèle, de la racine jusqu’au dernier niveau. Les dossiers manquants sont créés automatiquement.Pour placer le modèle dans un dossier, écrivez un champ folder pour chaque niveau du chemin. Par exemple, pour le placer dans le dossier Letters > Business :
writer.WriteField("folder", "Letters")
writer.WriteField("folder", "Business")
Une requête GET /template renvoie tous les modèles de votre compte :
request, err := http.NewRequest("GET", apiURL+"/template", nil)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
var templates []map[string]any
if err := json.Unmarshal(body, &templates); err != nil {
panic(err)
}
for _, template := range templates {
fmt.Println(template["id"], template["name"])
}
Pour lister uniquement les modèles d’un dossier, répétez le paramètre de requête folder pour chaque niveau du chemin. Par exemple, pour lister les modèles du dossier Letters > Business :
request, err := http.NewRequest("GET", apiURL+"/template?folder=Letters&folder=Business", nil)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
Seuls les modèles placés directement dans ce dossier sont renvoyés. Les modèles de ses sous-dossiers ne sont pas inclus. Pour en savoir plus, découvrez comment organiser les modèles dans des dossiers avec l’API.
Pour récupérer un seul modèle, appelez GET /template/{id} avec son ID :
templateID := "bet2oQirk0pSd9ctH9Qu"
request, err := http.NewRequest("GET", apiURL+"/template/"+templateID, nil)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
var template map[string]any
if err := json.Unmarshal(body, &template); err != nil {
panic(err)
}
fmt.Println(template["tags"].(map[string]any)["valid"])
C’est utile, par exemple, pour vérifier quelles balises de fusion le modèle attend avant de générer des documents.
Une requête PUT /template/{id} met à jour un modèle. Tous les paramètres sont facultatifs, n’envoyez donc que ceux que vous souhaitez modifier. Par exemple, pour envoyer une nouvelle version du fichier et renommer le modèle :
templateID := "bet2oQirk0pSd9ctH9Qu"
file, err := os.Open("Business Letter v2.docx")
if err != nil {
panic(err)
}
defer file.Close()
var form bytes.Buffer
writer := multipart.NewWriter(&form)
part, err := writer.CreateFormFile("file", "Business Letter v2.docx")
if err != nil {
panic(err)
}
if _, err := io.Copy(part, file); err != nil {
panic(err)
}
writer.WriteField("name", "Business Letter v2")
writer.Close()
request, err := http.NewRequest("PUT", apiURL+"/template/"+templateID, &form)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
request.Header.Set("Content-Type", writer.FormDataContentType())
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
var template map[string]any
if err := json.Unmarshal(body, &template); err != nil {
panic(err)
}
Comme pour la création d’un modèle, le corps doit être en multipart/form-data, avec l’en-tête Content-Type défini sur writer.FormDataContentType(). En plus de file et name, les paramètres facultatifs suivants peuvent être écrits dans le formulaire :
delimiters : Les nouveaux délimiteurs, envoyés sous forme de chaîne JSON. S’ils sont fournis, le modèle est à nouveau analysé pour détecter les balises de fusion selon les nouveaux délimiteurs. Lorsqu’un nouveau file est envoyé sans delimiters, les délimiteurs actuels sont utilisés.region : Déplace le modèle vers une autre région, soit us, eu, uk ou au. Les documents générés ensuite sont stockés dans la nouvelle région, tandis que les documents existants restent dans leur région actuelle.folder : Déplace le modèle vers un autre dossier, avec un champ folder pour chaque niveau du chemin. Envoyez "[]" pour sortir le modèle de tout dossier.enhanced_syntax : Définissez sur "true" ou "false" pour activer ou désactiver la syntaxe avancée.versioning_enabled : Définissez sur "true" ou "false" pour activer ou désactiver l’historique des versions, si votre forfait le permet.Pour supprimer un modèle, envoyez une requête DELETE /template/{id}. L’API répond avec un statut 204 No Content en cas de succès :
templateID := "bet2oQirk0pSd9ctH9Qu"
request, err := http.NewRequest("DELETE", apiURL+"/template/"+templateID, nil)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
Vous générez des documents avec une requête POST /document, en transmettant le template_id et le paramètre data, utilisé pour remplacer les balises de fusion :
payload, err := json.Marshal(map[string]any{
"template_id": "bet2oQirk0pSd9ctH9Qu",
"data": map[string]string{
"Date": "October 4, 2026",
"Name": "Emily Carter",
"Job Title": "Operations Manager",
"Company Name": "Harbor Point Consulting",
"Street Address": "118 West Street",
"City": "Annapolis",
"State": "Maryland",
"Zip Code": "21405",
"Email": "emily.carter@example.com",
"Phone": "(410) 555-0142",
},
"output_format": ".pdf",
})
if err != nil {
panic(err)
}
request, err := http.NewRequest("POST", apiURL+"/document", bytes.NewReader(payload))
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
request.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
var document map[string]any
if err := json.Unmarshal(body, &document); err != nil {
panic(err)
}
fmt.Println(document["document_uri"])
La réponse contient les propriétés du document :
{
"created": 1791125416372,
"template_id": "bet2oQirk0pSd9ctH9Qu",
"name": "Business Letter",
"format": ".pdf",
"data_length": 1,
"filename": "Business Letter.pdf",
"document_uri": "https://firebasestorage.googleapis.com/v0/b/storage.us.docugenerate.com/o/documents%2FiESelthRt4uaYQRTemrL%2FBusiness%20Letter.pdf?alt=media&token=c4b259ec-249b-4b35-a62f-6a8dc0da75f3",
"id": "iESelthRt4uaYQRTemrL"
}
Le paramètre output_format peut valoir .docx (par défaut), .pdf, .doc, .odt, .txt, .html, .png ou une version PDF/A. Vous pouvez aussi fusionner des fichiers PDF à la fin du document généré avec merge_with, ou ajouter des pièces jointes avec attach.
Télécharger le fichier
Le champ document_uri pointe vers le fichier généré, que vous pouvez télécharger et enregistrer sur le disque :
file, err := http.Get(document["document_uri"].(string))
if err != nil {
panic(err)
}
defer file.Body.Close()
if file.StatusCode >= 400 {
panic(fmt.Sprintf("Download failed with status %d", file.StatusCode))
}
content, err := io.ReadAll(file.Body)
if err != nil {
panic(err)
}
if err := os.WriteFile(document["filename"].(string), content, 0644); err != nil {
panic(err)
}
Recevoir le fichier directement
Si vous ne voulez pas que le document soit stocké dans le cloud, définissez l’en-tête Accept sur application/octet-stream. L’API renvoie alors le fichier binaire au lieu du JSON :
payload, err := json.Marshal(map[string]any{
"template_id": "bet2oQirk0pSd9ctH9Qu",
"data": map[string]string{
"Date": "October 4, 2026",
"Name": "Emily Carter",
"Job Title": "Operations Manager",
"Company Name": "Harbor Point Consulting",
"Street Address": "118 West Street",
"City": "Annapolis",
"State": "Maryland",
"Zip Code": "21405",
"Email": "emily.carter@example.com",
"Phone": "(410) 555-0142",
},
"output_format": ".pdf",
})
if err != nil {
panic(err)
}
request, err := http.NewRequest("POST", apiURL+"/document", bytes.NewReader(payload))
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/octet-stream")
request.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
if err := os.WriteFile("Business Letter.pdf", body, 0644); err != nil {
panic(err)
}
fmt.Println(response.Header.Get("X-Document-Id"))
Génération de documents par lot
Pour générer plusieurs documents en une seule requête, passez une slice de maps dans data. Un document est généré pour chaque map :
payload, err := json.Marshal(map[string]any{
"template_id": "bet2oQirk0pSd9ctH9Qu",
"data": []map[string]string{
{"Date": "October 4, 2026", "Name": "Emily Carter", "Job Title": "Operations Manager", "Company Name": "Harbor Point Consulting", "Street Address": "118 West Street", "City": "Annapolis", "State": "Maryland", "Zip Code": "21405", "Email": "emily.carter@example.com", "Phone": "(410) 555-0142"},
{"Date": "October 4, 2026", "Name": "Daniel Brooks", "Job Title": "Logistics Coordinator", "Company Name": "Northfield Logistics", "Street Address": "2400 South Lamar Boulevard", "City": "Austin", "State": "Texas", "Zip Code": "78704", "Email": "daniel.brooks@example.com", "Phone": "(512) 555-0187"},
},
"output_format": ".pdf",
"single_file": true,
"page_break": true,
})
if err != nil {
panic(err)
}
request, err := http.NewRequest("POST", apiURL+"/document", bytes.NewReader(payload))
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
request.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
var document map[string]any
if err := json.Unmarshal(body, &document); err != nil {
panic(err)
}
Par défaut, tous les documents sont combinés dans un seul fichier, avec un saut de page après chacun d’eux. Définissez page_break sur false pour supprimer les sauts de page.
Lorsque single_file vaut false, un fichier est généré par objet de données et tous les fichiers sont regroupés dans une archive .zip. Utilisez le paramètre name pour nommer l’archive, et output_name avec des balises de fusion pour donner à chaque fichier un nom dynamique, comme Letter for [Name] :
payload, err := json.Marshal(map[string]any{
"template_id": "bet2oQirk0pSd9ctH9Qu",
"data": []map[string]string{...},
"output_format": ".pdf",
"single_file": false,
"name": "Business Letters",
"output_name": "Letter for [Name]",
})
Cela génère une archive Business Letters.zip contenant Letter for Emily Carter.pdf et Letter for Daniel Brooks.pdf. Les balises de fusion de output_name doivent utiliser les mêmes délimiteurs que le modèle.
Utiliser un fichier de données
Pour générer des documents en masse à partir d’un fichier Excel ou CSV, envoyez le fichier dans une requête multipart/form-data. Un document est généré pour chaque ligne de la feuille de calcul. Si le fichier contient plusieurs feuilles, indiquez le paramètre sheet pour choisir celle à utiliser.
file, err := os.Open("Data.xlsx")
if err != nil {
panic(err)
}
defer file.Close()
var form bytes.Buffer
writer := multipart.NewWriter(&form)
writer.WriteField("template_id", "bet2oQirk0pSd9ctH9Qu")
part, err := writer.CreateFormFile("file", "Data.xlsx")
if err != nil {
panic(err)
}
if _, err := io.Copy(part, file); err != nil {
panic(err)
}
writer.WriteField("output_format", ".pdf")
writer.Close()
request, err := http.NewRequest("POST", apiURL+"/document", &form)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
request.Header.Set("Content-Type", writer.FormDataContentType())
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
L’utilisation d’un fichier de données est une autre forme de génération par lot, donc les mêmes paramètres s’appliquent pour combiner les documents générés dans un seul fichier ou les regrouper dans une archive .zip avec un nom personnalisé pour chaque fichier.
Une requête GET /document renvoie les documents générés à partir d’un modèle, dont l’ID est passé dans le paramètre de requête template_id :
request, err := http.NewRequest("GET", apiURL+"/document?template_id=bet2oQirk0pSd9ctH9Qu", nil)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
var documents []map[string]any
if err := json.Unmarshal(body, &documents); err != nil {
panic(err)
}
for _, document := range documents {
fmt.Println(document["id"], document["name"], document["document_uri"])
}
Pour récupérer un seul document, appelez GET /document/{id} avec son ID :
documentID := "iESelthRt4uaYQRTemrL"
request, err := http.NewRequest("GET", apiURL+"/document/"+documentID, nil)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
var document map[string]any
if err := json.Unmarshal(body, &document); err != nil {
panic(err)
}
Une requête PUT /document/{id} renomme un document, le nom étant la seule propriété modifiable :
documentID := "iESelthRt4uaYQRTemrL"
payload, err := json.Marshal(map[string]string{"name": "Letter for Emily Carter"})
if err != nil {
panic(err)
}
request, err := http.NewRequest("PUT", apiURL+"/document/"+documentID, bytes.NewReader(payload))
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
request.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}
var document map[string]any
if err := json.Unmarshal(body, &document); err != nil {
panic(err)
}
Pour supprimer un document, envoyez une requête DELETE /document/{id}. L’API répond avec un statut 204 No Content en cas de succès :
documentID := "iESelthRt4uaYQRTemrL"
request, err := http.NewRequest("DELETE", apiURL+"/document/"+documentID, nil)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", apiKey)
request.Header.Set("Accept", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode >= 400 {
panic(fmt.Sprintf("DocuGenerate API error %d: %s", response.StatusCode, body))
}